unit MuLog;

interface

type
  TOBJECT_LIFECYCLELogType = (logOBJECT_LIFECYCLE);
  THttpHeadersLogType = (logHttpHeaders);
  TIoOperationsLogType = (logIoOperations);
  TThreadLifecycleLogType = (logThreadLifecycle);

procedure Log(LogType: TOBJECT_LIFECYCLELogType; const ClassName: string; const Ptr: string); overload;
procedure Log(LogType: THttpHeadersLogType; const Guid: TGuid; HttpCode: Integer; ContentLength: Int64); overload;
procedure Log(LogType: TIoOperationsLogType; const FileName: string; Operation: Integer; Size: Int64); overload;
procedure Log(LogType: TThreadLifecycleLogType; WasBorn: TDateTime; WasDead: TDateTime; BornThreadId: Integer; DeadThreadId: Integer); overload;

implementation

const
  MuLogDll = 'MuLog.dll';

procedure LogInit(DbSignature: PChar); stdcall; external MuLogDll name 'LogInit';
procedure LogDone(); stdcall; external MuLogDll name 'LogDone';
function LogAlloc(Size: Integer): Pointer; stdcall; external MuLogDll name 'LogAlloc';
procedure LogFree(Data: Pointer); stdcall; external MuLogDll name 'LogFree';
procedure LogAdd(Data: Pointer); stdcall; external MuLogDll name 'LogAdd';

const
  DB_SIGNATURE = ''
    + 'T OBJECT_LIFECYCLE F ClassName:2:255 F Ptr:2:16 T HttpHeader'
    + 's IF Guid:4:0 F HttpCode:1:4 F ContentLength:1:8 T IoOperati'
    + 'ons F FileName:2:200 F Operation:1:4 F Size:1:8 T ThreadLife'
    + 'cycle F WasBorn:16:8 F WasDead:16:8 F BornThreadId:1:4 F Dea'
    + 'dThreadId:1:4'
  ;

type
  TLogPointer = class
    Base: Pointer;
    Pos: PChar;
    constructor Create(Size: Integer);
    destructor Destroy(); override;
    procedure Put(const Data; Size: Integer); overload;
    procedure Put(const S: string); overload;
    procedure Commit();
  end;

constructor TLogPointer.Create(Size: Integer);
begin
  inherited Create();
  Base := LogAlloc(Size);
  Pos := Base;
end;

destructor TLogPointer.Destroy();
begin
  LogFree(Base);
  inherited Destroy();
end;

procedure TLogPointer.Put(const Data; Size: Integer);
begin
  Move(Data, Pos^, Size);
  Pos := Pos + Size;
end;

procedure TLogPointer.Put(const S: string);
var
  Size: Integer;
begin
  Size := Length(S);
  Put(Size, 4);
  if Size > 0 then
    Put(S[1], Size);
end;

procedure TLogPointer.Commit();
begin
  LogAdd(Base);
end;

procedure Log(LogType: TOBJECT_LIFECYCLELogType; const ClassName: string; const Ptr: string);
var
  P: TLogPointer;
  LogTypeAsInt: Integer;
  Mask: Cardinal;
begin
  P := TLogPointer(16 + Length(ClassName) + Length(Ptr));
  try
    LogTypeAsInt := Ord(LogType);
    Mask := $00000003;

    P.Put(LogTypeAsInt, 4);
    P.Put(Mask, 4);
    P.Put(ClassName);
    P.Put(Ptr);

    P.Commit();
  finally
    P.Free();
  end;
end;

procedure Log(LogType: THttpHeadersLogType; const Guid: TGuid; HttpCode: Integer; ContentLength: Int64);
var
  P: TLogPointer;
  LogTypeAsInt: Integer;
  Mask: Cardinal;
begin
  P := TLogPointer(20);
  try
    LogTypeAsInt := Ord(LogType);
    Mask := $00000007;

    P.Put(LogTypeAsInt, 4);
    P.Put(Mask, 4);
    P.Put(Guid, 0);
    P.Put(HttpCode, 4);
    P.Put(ContentLength, 8);

    P.Commit();
  finally
    P.Free();
  end;
end;

procedure Log(LogType: TIoOperationsLogType; const FileName: string; Operation: Integer; Size: Int64);
var
  P: TLogPointer;
  LogTypeAsInt: Integer;
  Mask: Cardinal;
begin
  P := TLogPointer(24 + Length(FileName));
  try
    LogTypeAsInt := Ord(LogType);
    Mask := $00000007;

    P.Put(LogTypeAsInt, 4);
    P.Put(Mask, 4);
    P.Put(Operation, 4);
    P.Put(Size, 8);
    P.Put(FileName);

    P.Commit();
  finally
    P.Free();
  end;
end;

procedure Log(LogType: TThreadLifecycleLogType; WasBorn: TDateTime; WasDead: TDateTime; BornThreadId: Integer; DeadThreadId: Integer);
var
  P: TLogPointer;
  LogTypeAsInt: Integer;
  Mask: Cardinal;
begin
  P := TLogPointer(32);
  try
    LogTypeAsInt := Ord(LogType);
    Mask := $0000000F;

    P.Put(LogTypeAsInt, 4);
    P.Put(Mask, 4);
    P.Put(WasBorn, 8);
    P.Put(WasDead, 8);
    P.Put(BornThreadId, 4);
    P.Put(DeadThreadId, 4);

    P.Commit();
  finally
    P.Free();
  end;
end;

procedure Initialize();
begin
  LogInit(DB_SIGNATURE);
end;

procedure Finalize();
begin
  LogDone();
end;

initialization
  Initialize();

finalization
  Finalize();

end.
